//
//  Graph.cpp
//  IA2
//
//  Created by Etienne Lecouturier on 25/01/13.
//  Copyright (c) 2013 Etienne Lecouturier. All rights reserved.
//

#include <iostream>
#include <ctime>
#include "../include/graph.h"

using namespace std;

Graph::Graph(Board mboard, time_t startTime) : board(mboard)
{
    ourTurn = true;
    depth = 0;
    heuristic = board.computeHeuristic(depth);
    time_t currentTime;
    time(&currentTime);
    double d = difftime(currentTime, startTime);
    //cout << "time to compute graph : " << d << "ms"<< endl;
    //if (d < 2) {
        // compute euristic.
        // if there is enough time left, compute possible action and add new children.
        vector<moves> possibleMoves = board.getOurPossibleMoves();
        cout << "oo" << possibleMoves.size() << endl;
        for(int i = 0; i < possibleMoves.size(); i++) {
            //cout << "Nouvelle branche numero " << i << endl;
            Graph child = Graph(board, possibleMoves[i], !ourTurn, depth+1, startTime);
            addChildren(child);
        }
    //}
}

Graph::Graph(Board mboard, moves actions2, bool isOurTurn, int depth2, time_t startTime) : ourTurn(isOurTurn)
{
    actions = actions2;
    Board board = mboard.copyBoard();
    depth = depth2;

    board.applyMove(actions);

    time_t currentTime;
    time(&currentTime);
    double d = difftime(currentTime, startTime);
    //cout << "time to compute graph : " << d << "ms"<< endl;
    //if (d < 2) {
    heuristic = board.computeHeuristic(depth);
    if (depth < 5) {

        //cout << "h = " << heuristic << endl;

        // if there is enough time left, compute possible action and add new children.
        vector<moves> possibleMoves;
        if (ourTurn) {
            possibleMoves = board.getOurPossibleMoves();
            //cout << "PossibleMoves size =" << possibleMoves.size() << endl;
        }
        else {
            possibleMoves = board.getTheirPossibleMoves();
        }

        for(int i = 0; i < possibleMoves.size(); i++) {

            Graph child = Graph(board, possibleMoves[i], !isOurTurn, depth+1, startTime);
            addChildren(child);


        }
    }

}

void Graph::addChildren(Graph g)
{

    childrenList.push_back(g);

}

vector<Graph> Graph::getChildren()
{
    return childrenList;
}

moves Graph::getMovesToSend()
{
    moves moveToSend = moves();
    float maxValue = -10000;
    int iMax = 20;
    for(int i = 0; i < childrenList.size(); i++) {

        float minmaxChild = childrenList[i].applyMinMax();

        //cout << "Petit i = " << i << " mm =" << minmaxChild << endl;

        if (minmaxChild > maxValue){
            maxValue = minmaxChild;
            moveToSend = childrenList[i].getMovesDone();
            iMax = i;
        }
    }
    //cout << "minmaxChild = " << maxValue << endl;
    //cout << "iMax =" << iMax << endl;

    //cout << "Returned" << endl;
    return moveToSend;
}

float Graph::applyMinMax()
{
    minmaxValue = ourTurn ? -10000 : 10000;
    for(int i = 0; i < childrenList.size(); i++) {
        int minmaxChild = childrenList[i].applyMinMax();
        if (ourTurn && (minmaxChild > minmaxValue)){
            minmaxValue = minmaxChild;
        }
        if (!ourTurn && (minmaxChild < minmaxValue)) {
            minmaxValue = minmaxChild;
        }
    }
    // In case the node is a leaf.
    if (childrenList.size() == 0) {
        //cout << "ABCDEFG Heuristic =" << heuristic << endl;
        minmaxValue = heuristic;
    }
    float result = heuristic/(6-depth);

    //cout << "Depth "<< depth << endl;
    //float result = heuristic/(depth);
    return result + minmaxValue;
    //return result;
}

float Graph::applyAlphaBeta(float malpha, float mbeta)
{
    if (childrenList.size() == 0) {
        return heuristic;
    }
    else {
        if (ourTurn) { /* MAX */
            float val = -MAX_INT;
            for(int i = 0; i < childrenList.size(); i++) {
                val = std::max(val, childrenList[i].applyAlphaBeta(malpha, mbeta));
                if (val >= mbeta) { /* coupure beta */
                    return val;
                }
                malpha = std::max(val, malpha);
            }
        }
        else {
            float val = MAX_INT;
            for(int i = 0; i < childrenList.size(); i++) {
                val = std::min(val, childrenList[i].applyAlphaBeta(malpha, mbeta));
                if (val <= malpha) { /* coupure alpha */
                    return val;
                }
                mbeta = std::min(val, mbeta);
            }
        }
    }
}

bool Graph::isOurTurn()
{
    return ourTurn;
}

moves Graph::getMovesDone()
{
    return actions;
}
